<!DOCTYPE html>
          <head>
        <meta charset="utf-8">
            
            <title>
                [Android]从通过view.post()获取View宽高谈Android消息机制 | ttdevs
            </title>
            <meta content="width=device-width, initial-scale=1" name="viewport">
            <meta name="theme-color" content="#4184f3">
            
            
            <link href="/favicon.ico" rel="icon"/>
            

            <link rel="stylesheet" href="/css/highlight.light.css">
            <link rel="stylesheet" href="/css/prism-customize.css">
            <link rel="stylesheet" href="/css/nav-icon.css">
            <link rel="stylesheet" href="/css/waves.min.css">
            <link rel="stylesheet" href="/css/jquery.tocify.css">
            <link rel="stylesheet" href="/css/main.css">
            <link rel="stylesheet" href="/css/nav-indicator.css">
            
  

  
  <!-- 谷歌统计 -->
  <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-97465173-1', 'auto');
    ga('send', 'pageview');

  </script>
  
            </meta>
        </meta>
    </head>

    <body>
        <header>
            <!-- cover image or sth. -->
        </header>
        <div id="main" class="m-scene">
            
<div class="nav-wrapper">

    <div class="container">
        <nav>
            <div class="logo wave">
                <a href="/" id="logo">
                    ttdevs
                </a>
            </div>
            <div class="nav-toggle-icon" >
                <div class="material-hamburger">
                    <span>
                    </span>
                    <span>
                    </span>
                    <span>
                    </span>
                </div>
            </div>
            <div class="menu-wrapper">
                <div class="nav-indicator">
                </div>
                <ul class="menus">
                    
                     
                        <li>
                            <a class="wave " href="/">
                                首页
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/archives">
                                归档
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/about">
                                关于
                            </a>
                        </li>
                     
                    
                   
                </ul>
            </div>
        </nav>
    </div>
</div>
            <div class="container content">
                <div class="scene_element scene_element--fadein">
                    <div class="row">
    <div class="main">
        <article>
          
          <header class="post-header with-cover" style="background-image:url('/2017/07/26/Android-从通过view-post-获取View宽高谈Android消息机制/cover.jpg')" >
          
          </header>
          <h1 class="post-title">[Android]从通过view.post()获取View宽高谈Android消息机制</h1>

          <section class="post-info">
            <span class="post-date">2017/07/26</span>
            
            <span class="post-category">
                <a class="article-category-link" href="/categories/技术/">技术</a>
            </span>
            
            
            <span class="post-tags">
              <ul class="post-tag-list"><li class="post-tag-list-item"><a class="post-tag-list-link" href="/tags/Android/">Android</a></li></ul>
            </span>
            
          </section>

          <section class="post-content">
            <h2 id="0x00-通过view-post-获取View宽高"><a href="/2017/07/26/Android-从通过view-post-获取View宽高谈Android消息机制/#0x00-通过view-post-获取View宽高" class="headerlink" title="0x00 通过view.post()获取View宽高"></a>0x00 通过view.post()获取View宽高</h2><p>有时候我们希望在界面初始话的时候根据View的尺寸来做一些相关的操作（调整），那如何获取View的尺寸呢？</p>
<ul>
<li><p>在Activity的 <code>onCreate()</code> 方法中 delay 几百毫秒<br><br>  由于我们知道在 <code>onCreate()</code> 中直接获取View的尺寸得到的宽高都是0，这个不经思考的答案相信很多人在用。</p>
</li>
<li><p>如果你Google过答案，一般会有下面这几种方法：</p>
<ul>
<li><p>onWindowFocusChanged</p>
<p>  重写Activity的 <code>onWindowFocusChanged()</code> 方法，当Activity的焦点状态发生变化时会回调这个方法，参数 <code>hasFocus</code> 为 <code>true</code> 时表示已经获取到焦点，这个时候View的绘制已经完成，也就可以获取到View的尺寸了。</p>
<pre><code>@Override
public void onWindowFocusChanged(boolean hasFocus) {
  super.onWindowFocusChanged(hasFocus);
  if (hasFocus) {
      System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;onWindowFocusChanged&quot; + tvLog.getWidth());
      System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;onWindowFocusChanged&quot; + tvLog.getHeight());
  }
}
</code></pre></li>
<li><p>ViewTreeObserver.addOnPreDrawListener or .addOnGlobalLayoutListener</p>
<p>  这个方法的缺点是会多次调用。</p>
<pre><code>private void getViewSize(){
    tvLog.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;addOnPreDrawListener&quot; + tvLog.getWidth());
            System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;addOnPreDrawListener&quot; + tvLog.getHeight());
            return true;
        }
    });
    tvLog.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;addOnGlobalLayoutListener&quot; + tvLog.getWidth());
            System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;addOnGlobalLayoutListener&quot; + tvLog.getHeight());
        }
    });
}
</code></pre></li>
<li><p>view.post()</p>
<p>  这中方法是我个人推荐的方法，接下来的内容会着重分析。</p>
<pre><code>private void getViewSize() {
    tvLog.post(new Runnable() {
        @Override
        public void run() {
            System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;post&quot; + tvLog.getWidth());
            System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;post&quot; + tvLog.getHeight());
        }
    });
}
</code></pre></li>
<li><p>当然，还会有一些其他方法，比如手动measure，在View内部获取等等</p>
</li>
</ul>
</li>
</ul>
<p><a href="https://stackoverflow.com/questions/3591784/getwidth-and-getheight-of-view-returns-0" target="_blank" rel="external">可以参考这里</a></p>
<p>以上的几种方法都可以，下面针对View.post做一个分析。</p>
<h2 id="0x01-Android系统的消息机制"><a href="/2017/07/26/Android-从通过view-post-获取View宽高谈Android消息机制/#0x01-Android系统的消息机制" class="headerlink" title="0x01 Android系统的消息机制"></a>0x01 Android系统的消息机制</h2><p>Android系统的消息机制，是每个初学者都必须掌握的基础知识。以前学习的时候有看过，初面试的时候也去突击过，但是都深入的去理解去掌握，惭愧呢。</p>
<p>对于一个消息系统，大家可以类比下生活中的快递系统：有发件人，有收件人，有快递公司，当然还有最重要的信件。通过这个系统我们可以将不同的信件投送到不同的地方，比如从个人投送到政府部门，从国内投送到国外等。下面的表格看起来会更直观一些：</p>
<table>
<thead>
<tr>
<th style="text-align:center">快递系统</th>
<th style="text-align:center">Android消息系统</th>
<th style="text-align:center">职责</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">发件人</td>
<td style="text-align:center">Handler</td>
<td style="text-align:center">发送消息</td>
</tr>
<tr>
<td style="text-align:center">收件人</td>
<td style="text-align:center">Handler</td>
<td style="text-align:center">接收处理消息</td>
</tr>
<tr>
<td style="text-align:center">快件</td>
<td style="text-align:center">Message</td>
<td style="text-align:center">发送的内容</td>
</tr>
<tr>
<td style="text-align:center">快递公司</td>
<td style="text-align:center">Looper / MessageQueue</td>
<td style="text-align:center">接收消息、传递消息、分发消息</td>
</tr>
</tbody>
</table>
<p>相信这个简单的对比对理解消息机制会有很大帮助。接下来我们再来看看这个系统是如何运行的。</p>
<p>先看一下消息系统的简单使用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> <span class="keyword">implements</span> <span class="title">View</span>.<span class="title">OnClickListener</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Handler mHandler = <span class="keyword">new</span> Handler() &#123;</div><div class="line"></div><div class="line">        <span class="meta">@Override</span></div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">handleMessage</span><span class="params">(Message msg)</span> </span>&#123;</div><div class="line">            <span class="keyword">super</span>.handleMessage(msg);</div><div class="line"></div><div class="line">            printMsg(<span class="string">"handleMessage:"</span> + msg.obj);</div><div class="line">        &#125;</div><div class="line">    &#125;;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState);</div><div class="line">        setContentView(R.layout.activity_main);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</div><div class="line">        <span class="keyword">switch</span> (view.getId()) &#123;</div><div class="line">            <span class="keyword">case</span> R.id.btSendMsg:</div><div class="line">                defaultSendMsg();</div><div class="line">                <span class="keyword">break</span>;</div><div class="line"></div><div class="line">            <span class="keyword">default</span>:</div><div class="line">                <span class="keyword">break</span>;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">defaultSendMsg</span><span class="params">()</span> </span>&#123;</div><div class="line">        Message msg = <span class="keyword">new</span> Message();</div><div class="line">        msg.obj = <span class="string">"这是最简单的使用方法，但无实际意义"</span>;</div><div class="line">        mHandler.sendMessage(msg);</div><div class="line">        printMsg(<span class="string">"Is MainLooper: "</span> + (mHandler.getLooper() == getMainLooper()));</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">printMsg</span><span class="params">(String msg)</span> </span>&#123;</div><div class="line">        System.out.println(<span class="string">"&gt;&gt;&gt;&gt;&gt;"</span> + msg);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>输出信息：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">I/System.out: &gt;&gt;&gt;&gt;&gt;Is MainLooper: true</div><div class="line">I/System.out: &gt;&gt;&gt;&gt;&gt;handleMessage:这是最简单的使用方法，但无实际意义</div></pre></td></tr></table></figure>
<p>从这里可以看到，我们需要先创建一个Handler对象，然后通过这个Handler发送消息，然后在Handler中处理接收到的消息。另外我们还看到我们的Looper对象是主线程的Looper，这是因为我们是在Activity跑的这段代码。下面我们来跟一下代码。</p>
<p>从Handler的构造方法开始：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">Handler</span><span class="params">(Callback callback, <span class="keyword">boolean</span> async)</span> </span>&#123;</div><div class="line">   ...</div><div class="line"></div><div class="line">   mLooper = Looper.myLooper();</div><div class="line">   <span class="keyword">if</span> (mLooper == <span class="keyword">null</span>) &#123;</div><div class="line">       <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(</div><div class="line">           <span class="string">"Can't create handler inside thread that has not called Looper.prepare()"</span>);</div><div class="line">   &#125;</div><div class="line">   mQueue = mLooper.mQueue;</div><div class="line">   mCallback = callback; <span class="comment">// 这个对象我们在后面的dispatchMessage时会用到</span></div><div class="line">   mAsynchronous = async;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>这里我们看到，通过 <code>Looper.myLooper()</code> 获取到一个Looper对象，然后再从这个Looper对象中拿到一个MessageQueue对象（mQueue），这样我们很容易得到结论——消息队列是位于Looper中的。那MessageQueue是什么时候创建的，又是怎样处理消息的？带着这些疑问我们接下来看 <code>Handler.sendMessage(msg)</code> (<code>sendMessage()</code> 最终会调到 <code>sendMessageAtTime()</code>)：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">sendMessageAtTime</span><span class="params">(Message msg, <span class="keyword">long</span> uptimeMillis)</span> </span>&#123;</div><div class="line">   MessageQueue queue = mQueue;</div><div class="line">   <span class="keyword">if</span> (queue == <span class="keyword">null</span>) &#123;</div><div class="line">       RuntimeException e = <span class="keyword">new</span> RuntimeException(</div><div class="line">               <span class="keyword">this</span> + <span class="string">" sendMessageAtTime() called with no mQueue"</span>);</div><div class="line">       Log.w(<span class="string">"Looper"</span>, e.getMessage(), e);</div><div class="line">       <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">   &#125;</div><div class="line">   <span class="keyword">return</span> enqueueMessage(queue, msg, uptimeMillis);</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">enqueueMessage</span><span class="params">(MessageQueue queue, Message msg, <span class="keyword">long</span> uptimeMillis)</span> </span>&#123;</div><div class="line">   msg.target = <span class="keyword">this</span>;</div><div class="line">   <span class="keyword">if</span> (mAsynchronous) &#123;</div><div class="line">       msg.setAsynchronous(<span class="keyword">true</span>);</div><div class="line">   &#125;</div><div class="line">   <span class="keyword">return</span> queue.enqueueMessage(msg, uptimeMillis);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>sendMessageAtTime()</code> 会传入两个参数：<code>Message</code> 和 <code>uptimeMillis</code>，<code>uptimeMillis</code> 的意思是消息将会在这个时刻执行（不是非常精确），这种情况比如常见的 <code>postDelay</code>。在 <code>enqueueMessage()</code> 方法中，会根据这个值将消息加入消息队列，我们还可以看到，在放入队列之前Message的 <code>target</code> 被设置为当前的Handler对象——透露下这个是保证之后消息投递的时候仍分发给当前Handler，这个很重要！</p>
<p>再来看下上面提到的 Looper 和 MessageQueue：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Looper</span> </span>&#123;</div><div class="line">    ...</div><div class="line">    <span class="comment">// sThreadLocal.get() will return null unless you've called prepare().</span></div><div class="line">    <span class="keyword">static</span> <span class="keyword">final</span> ThreadLocal&lt;Looper&gt; sThreadLocal = <span class="keyword">new</span> ThreadLocal&lt;Looper&gt;();</div><div class="line">    ...</div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">prepare</span><span class="params">(<span class="keyword">boolean</span> quitAllowed)</span> </span>&#123;</div><div class="line">       <span class="keyword">if</span> (sThreadLocal.get() != <span class="keyword">null</span>) &#123;</div><div class="line">           <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"Only one Looper may be created per thread"</span>);</div><div class="line">       &#125;</div><div class="line">       sThreadLocal.set(<span class="keyword">new</span> Looper(quitAllowed));</div><div class="line">    &#125;</div><div class="line">    </div><div class="line">    <span class="comment">/**</span></div><div class="line">    * Initialize the current thread as a looper, marking it as an</div><div class="line">    * application's main looper. The main looper for your application</div><div class="line">    * is created by the Android environment, so you should never need</div><div class="line">    * to call this function yourself.  See also: &#123;<span class="doctag">@link</span> #prepare()&#125;</div><div class="line">    */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">prepareMainLooper</span><span class="params">()</span> </span>&#123;</div><div class="line">       prepare(<span class="keyword">false</span>);</div><div class="line">       <span class="keyword">synchronized</span> (Looper.class) &#123;</div><div class="line">           <span class="keyword">if</span> (sMainLooper != <span class="keyword">null</span>) &#123;</div><div class="line">               <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"The main Looper has already been prepared."</span>);</div><div class="line">           &#125;</div><div class="line">           sMainLooper = myLooper();</div><div class="line">       &#125;</div><div class="line">    &#125;</div><div class="line">    </div><div class="line">    <span class="comment">/**</span></div><div class="line">    * Returns the application's main looper, which lives in the main thread of the application.</div><div class="line">    */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Looper <span class="title">getMainLooper</span><span class="params">()</span> </span>&#123;</div><div class="line">       <span class="keyword">synchronized</span> (Looper.class) &#123;</div><div class="line">           <span class="keyword">return</span> sMainLooper;</div><div class="line">       &#125;</div><div class="line">    &#125;</div><div class="line">    </div><div class="line">    <span class="comment">/**</span></div><div class="line">    * Run the message queue in this thread. Be sure to call</div><div class="line">    * &#123;<span class="doctag">@link</span> #quit()&#125; to end the loop.</div><div class="line">    */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</div><div class="line">       <span class="keyword">final</span> Looper me = myLooper();</div><div class="line">       <span class="keyword">if</span> (me == <span class="keyword">null</span>) &#123;</div><div class="line">           <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"No Looper; Looper.prepare() wasn't called on this thread."</span>);</div><div class="line">       &#125;</div><div class="line">       <span class="keyword">final</span> MessageQueue queue = me.mQueue;</div><div class="line">       ...</div><div class="line">       <span class="keyword">for</span> (;;) &#123;</div><div class="line">           Message msg = queue.next(); <span class="comment">// might block</span></div><div class="line">           <span class="keyword">if</span> (msg == <span class="keyword">null</span>) &#123;</div><div class="line">               <span class="comment">// No message indicates that the message queue is quitting.</span></div><div class="line">               <span class="keyword">return</span>;</div><div class="line">           &#125;</div><div class="line">    </div><div class="line">           ...</div><div class="line">    </div><div class="line">           msg.target.dispatchMessage(msg);</div><div class="line">    </div><div class="line">           <span class="keyword">if</span> (logging != <span class="keyword">null</span>) &#123;</div><div class="line">               logging.println(<span class="string">"&lt;&lt;&lt;&lt;&lt; Finished to "</span> + msg.target + <span class="string">" "</span> + msg.callback);</div><div class="line">           &#125;</div><div class="line">    </div><div class="line">           ...</div><div class="line">    </div><div class="line">           msg.recycleUnchecked();</div><div class="line">       &#125;</div><div class="line">    &#125;</div><div class="line">    </div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="title">Looper</span><span class="params">(<span class="keyword">boolean</span> quitAllowed)</span> </span>&#123;</div><div class="line">        mQueue = <span class="keyword">new</span> MessageQueue(quitAllowed);</div><div class="line">        mThread = Thread.currentThread();</div><div class="line">    &#125;</div><div class="line">      </div><div class="line">    <span class="comment">/**</span></div><div class="line">    * Return the Looper object associated with the current thread.  Returns</div><div class="line">    * null if the calling thread is not associated with a Looper.</div><div class="line">    */</div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="meta">@Nullable</span> <span class="function">Looper <span class="title">myLooper</span><span class="params">()</span> </span>&#123;</div><div class="line">       <span class="keyword">return</span> sThreadLocal.get();</div><div class="line">    &#125;</div><div class="line">    </div><div class="line">    <span class="comment">/**</span></div><div class="line">    * Return the &#123;<span class="doctag">@link</span> MessageQueue&#125; object associated with the current</div><div class="line">    * thread.  This must be called from a thread running a Looper, or a</div><div class="line">    * NullPointerException will be thrown.</div><div class="line">    */</div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="meta">@NonNull</span> <span class="function">MessageQueue <span class="title">myQueue</span><span class="params">()</span> </span>&#123;</div><div class="line">       <span class="keyword">return</span> myLooper().mQueue;</div><div class="line">    &#125;</div><div class="line">    </div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="title">Looper</span><span class="params">(<span class="keyword">boolean</span> quitAllowed)</span> </span>&#123;</div><div class="line">       mQueue = <span class="keyword">new</span> MessageQueue(quitAllowed);</div><div class="line">       mThread = Thread.currentThread();</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>Looper的构造方法中只是创建了一个 MessageQueue 对象，同时这个方法是私有的，因此这个类无法在外部通过new来创建，。我们看到唯一创建的地方就是 <code>Looper.prepare()</code> 方法中，创建好之后直接被加入到ThreadLocal中。再来看我们刚才用到的 <code>Looper.myLooper()</code> 方法，这其中只有一行很尴尬的代码，<code>sThreadLocal.get()</code> ，它就是从ThreadLocal中获取 <code>属于当前线程的 Looper 对象</code>。关于 ThreadLocal，这个在我的<a href="http://blog.csdn.net/ttdevs/article/details/71375416" target="_blank" rel="external">另一篇文章中有介绍</a>——我们在线程中创建的变量，任何一个线程都可以访问并对其修改，但是我们通过LocalThread创建的变量，就只有当前线程可以访问了。</p>
<p>之前我们知道通过 Handler.sendMessage(msg) 将 Message 存入 MessageQueue 中，在上面的代码中我们可以看到，Looper.loop()中开了一个死循环，将消息从 MessageQueue 中取出然后进行分发。看到 MessageQueue 后我第一个想到就是阻塞队列，结果看了源码之后并不是这么简单。如果想看这个类的分析，可以参考<a href="http://blog.csdn.net/luoshengyang/article/details/6817933/" target="_blank" rel="external">这里</a>，这是最核心的部分，涉及到操作系统的知识，我就不卖弄了。但是这不影响我们将 MessageQueue 按照一个阻塞队列来理解。</p>
<p>再看下Looper是如何使用的。我们在Looper的类注释中可以看到这段信息：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line">  * Class used to run a message loop for a thread.  Threads by default do</div><div class="line">  * not have a message loop associated with them; to create one, call</div><div class="line">  * &#123;<span class="doctag">@link</span> #prepare&#125; in the thread that is to run the loop, and then</div><div class="line">  * &#123;<span class="doctag">@link</span> #loop&#125; to have it process messages until the loop is stopped.</div><div class="line">  *</div><div class="line">  * &lt;p&gt;Most interaction with a message loop is through the</div><div class="line">  * &#123;<span class="doctag">@link</span> Handler&#125; class.</div><div class="line">  *</div><div class="line">  * &lt;p&gt;This is a typical example of the implementation of a Looper thread,</div><div class="line">  * using the separation of &#123;<span class="doctag">@link</span> #prepare&#125; and &#123;<span class="doctag">@link</span> #loop&#125; to create an</div><div class="line">  * initial Handler to communicate with the Looper.</div><div class="line">  *</div><div class="line">  * &lt;pre&gt;</div><div class="line">  *  class LooperThread extends Thread &#123;</div><div class="line">  *      public Handler mHandler;</div><div class="line">  *</div><div class="line">  *      public void run() &#123;</div><div class="line">  *          Looper.prepare();</div><div class="line">  *</div><div class="line">  *          mHandler = new Handler() &#123;</div><div class="line">  *              public void handleMessage(Message msg) &#123;</div><div class="line">  *                  // process incoming messages here</div><div class="line">  *              &#125;</div><div class="line">  *          &#125;;</div><div class="line">  *</div><div class="line">  *          Looper.loop();</div><div class="line">  *      &#125;</div><div class="line">  *  &#125;&lt;/pre&gt;</div><div class="line">  */</div><div class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Looper</span> </span>&#123;...&#125;</div></pre></td></tr></table></figure>
<p>如果我们需要在自己的线程中实现消息机制，我们需要先执行 <code>Looper.prepare();</code>； 然后创建 Handler对象；最后再执行 <code>Looper.loop()</code>；这个顺序不能颠倒！最后我们再来将这个流程梳理一下：</p>
<ol>
<li><p>Looper.prepare()；</p>
<p> 初始化属于当前线程的 Looper 对象，然后放入 ThreadLocal 中。</p>
</li>
<li><p>new Handler()；</p>
<p> 为什么一定要在 <code>Looper.prepare()</code> 之后 <code>Looper.loop()</code> 之前创建Handler对象呢？ </p>
<p> 答：在 <code>Looper.prepare()</code> 之后是因为 Handler 的构造函数中需要提供当前线程的 Looper 对 象，这个 Looper 对象只能通过 <code>Looper.prepare()</code> 来创建。在 <code>Looper.loop()</code> 之前是因为Looper.loop()是个死循环，写在其后代码是执行不到的（看看最后留的那个问题～）。</p>
</li>
<li><p>Looper.loop();</p>
<p> 这个操作就是开始执行消息循环，处理消息。</p>
</li>
</ol>
<p>小结：</p>
<p>消息机制是Android系统中线程通信非常重要的一种方法。如果向另一个线程传递数据，我们可以在目标线程中启动消息机制，拿到这个线程Looper对象创建一个Handler，通过这个Handler就可以向目标线程发送消息了，反之亦然。</p>
<h2 id="0x03-HandlerThread、AsyncTask-和-UI-Thread"><a href="/2017/07/26/Android-从通过view-post-获取View宽高谈Android消息机制/#0x03-HandlerThread、AsyncTask-和-UI-Thread" class="headerlink" title="0x03 HandlerThread、AsyncTask 和 UI Thread"></a>0x03 HandlerThread、AsyncTask 和 UI Thread</h2><ul>
<li><p>HandlerThread</p>
<p>  从源码可以看到，这个类是对我们Android消息机制的一个封装。当我们需要自己去写一个在子线程工作然后将结果传到主线程的功能时可以考虑用这个类。下面提供一个简单的Demo：</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HandlerThreadActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> Handler mHandler = <span class="keyword">new</span> Handler()&#123;</div><div class="line">        <span class="meta">@Override</span></div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">handleMessage</span><span class="params">(Message msg)</span> </span>&#123;</div><div class="line">            <span class="keyword">super</span>.handleMessage(msg);</div><div class="line"></div><div class="line">            String threadName = Thread.currentThread().getName();</div><div class="line">            tvLog.setText(String.format(<span class="string">"当前线程：%s Msg：%s"</span>, threadName, msg.obj));</div><div class="line">        &#125;</div><div class="line">    &#125;;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> TextView tvLog;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState);</div><div class="line">        setContentView(R.layout.activity_handler_thread);</div><div class="line">        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);</div><div class="line">        setSupportActionBar(toolbar);</div><div class="line"></div><div class="line">        tvLog = (TextView)findViewById(R.id.tvLog);</div><div class="line"></div><div class="line">        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);</div><div class="line">        fab.setOnClickListener(<span class="keyword">new</span> View.OnClickListener() &#123;</div><div class="line">            <span class="meta">@Override</span></div><div class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</div><div class="line">                sendMessage();</div><div class="line">            &#125;</div><div class="line">        &#125;);</div><div class="line"></div><div class="line">        initData();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> Handler mWorker;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initData</span><span class="params">()</span> </span>&#123;</div><div class="line">        HandlerThread worker = <span class="keyword">new</span> HandlerThread(<span class="string">"worker"</span>);</div><div class="line">        worker.start();</div><div class="line">        mWorker = <span class="keyword">new</span> Handler(worker.getLooper());</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">sendMessage</span><span class="params">()</span> </span>&#123;</div><div class="line">        mWorker.post(<span class="keyword">new</span> Runnable() &#123;</div><div class="line">            <span class="meta">@Override</span></div><div class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">                print(<span class="string">"我工作在线程："</span> + Thread.currentThread().getName());</div><div class="line">                <span class="keyword">try</span> &#123;</div><div class="line">                    Thread.sleep(<span class="number">6</span> * <span class="number">1000</span>);</div><div class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</div><div class="line">                    e.printStackTrace();</div><div class="line">                &#125;</div><div class="line">                sendMsgToUI();</div><div class="line">            &#125;</div><div class="line"></div><div class="line">            <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">sendMsgToUI</span><span class="params">()</span></span>&#123;</div><div class="line">                Message msg = <span class="keyword">new</span> Message();</div><div class="line">                msg.obj = Thread.currentThread().getName() + <span class="string">"工作完成，这是结果"</span>;</div><div class="line">                    mHandler.sendMessage(msg);</div><div class="line">            &#125;</div><div class="line">        &#125;);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">(String msg)</span> </span>&#123;</div><div class="line">        System.out.println(<span class="string">"&gt;&gt;&gt;&gt;&gt;"</span> + msg);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>思路如下：</p>
<ol>
<li>创建HandlerThread对象，这个对象是一个线程</li>
<li>启动第一步创建的线程</li>
<li>创建一个Handler，并使用第一步创建的线程中的Looper</li>
<li>然后在主线程通过这个Handler向工作线程发任务</li>
<li>任务执行完毕后，使用在Activity（主线程）中的Handler发送消息，将结果从工作线程传回主线程</li>
</ol>
<ul>
<li><p>AsyncTask</p>
<p>  这是个非常强大的工具类，用到的知识点也非常多，曾经统治过网络库的编写。这里只讲跟我们消息系统相关的知识，先看一段源码：</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AsyncTask</span>&lt;<span class="title">Params</span>, <span class="title">Progress</span>, <span class="title">Result</span>&gt; </span>&#123;</div><div class="line">...</div><div class="line">    <span class="keyword">private</span> <span class="keyword">static</span> InternalHandler sHandler; </div><div class="line">...</div><div class="line">    <span class="comment">// 获取到Handler</span></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> Handler <span class="title">getHandler</span><span class="params">()</span> </span>&#123; </div><div class="line">        <span class="keyword">synchronized</span> (AsyncTask.class) &#123;</div><div class="line">            <span class="keyword">if</span> (sHandler == <span class="keyword">null</span>) &#123;</div><div class="line">                sHandler = <span class="keyword">new</span> InternalHandler();</div><div class="line">            &#125;</div><div class="line">            <span class="keyword">return</span> sHandler;</div><div class="line">        &#125;</div><div class="line">...</div><div class="line">    <span class="comment">// 在工作线程发送结果到主线程，这里获取到Message.target都是sHandler对象</span></div><div class="line">    <span class="function"><span class="keyword">private</span> Result <span class="title">postResult</span><span class="params">(Result result)</span> </span>&#123;</div><div class="line">        <span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</div><div class="line">        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,</div><div class="line">                <span class="keyword">new</span> AsyncTaskResult&lt;Result&gt;(<span class="keyword">this</span>, result));</div><div class="line">        message.sendToTarget();</div><div class="line">        <span class="keyword">return</span> result;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">...</div><div class="line">    <span class="comment">/**</span></div><div class="line">     * &lt;p&gt;Runs on the UI thread after &#123;<span class="doctag">@link</span> #doInBackground&#125;. The</div><div class="line">     * specified result is the value returned by &#123;<span class="doctag">@link</span> #doInBackground&#125;.&lt;/p&gt;</div><div class="line">     * </div><div class="line">     * &lt;p&gt;This method won't be invoked if the task was cancelled.&lt;/p&gt;</div><div class="line">     *</div><div class="line">     * <span class="doctag">@param</span> result The result of the operation computed by &#123;<span class="doctag">@link</span> #doInBackground&#125;.</div><div class="line">     *</div><div class="line">     * <span class="doctag">@see</span> #onPreExecute</div><div class="line">     * <span class="doctag">@see</span> #doInBackground</div><div class="line">     * <span class="doctag">@see</span> #onCancelled(Object) </div><div class="line">     */</div><div class="line">    <span class="meta">@SuppressWarnings</span>(&#123;<span class="string">"UnusedDeclaration"</span>&#125;)</div><div class="line">    <span class="meta">@MainThread</span> <span class="comment">// 这个方法里的代码都是在主线程执行了</span></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onPostExecute</span><span class="params">(Result result)</span> </span>&#123;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * Runs on the UI thread after &#123;<span class="doctag">@link</span> #publishProgress&#125; is invoked.</div><div class="line">     * The specified values are the values passed to &#123;<span class="doctag">@link</span> #publishProgress&#125;.</div><div class="line">     *</div><div class="line">     * <span class="doctag">@param</span> values The values indicating progress.</div><div class="line">     *</div><div class="line">     * <span class="doctag">@see</span> #publishProgress</div><div class="line">     * <span class="doctag">@see</span> #doInBackground</div><div class="line">     */</div><div class="line">    <span class="meta">@SuppressWarnings</span>(&#123;<span class="string">"UnusedDeclaration"</span>&#125;)</div><div class="line">    <span class="meta">@MainThread</span> <span class="comment">// 这个方法里的代码都是在主线程执行了</span></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onProgressUpdate</span><span class="params">(Progress... values)</span> </span>&#123;</div><div class="line">    &#125;</div><div class="line">...</div><div class="line">    <span class="comment">/**</span></div><div class="line">     * This method can be invoked from &#123;<span class="doctag">@link</span> #doInBackground&#125; to</div><div class="line">     * publish updates on the UI thread while the background computation is</div><div class="line">     * still running. Each call to this method will trigger the execution of</div><div class="line">     * &#123;<span class="doctag">@link</span> #onProgressUpdate&#125; on the UI thread.</div><div class="line">     *</div><div class="line">     * &#123;<span class="doctag">@link</span> #onProgressUpdate&#125; will not be called if the task has been</div><div class="line">     * canceled.</div><div class="line">     *</div><div class="line">     * <span class="doctag">@param</span> values The progress values to update the UI with.</div><div class="line">     *</div><div class="line">     * <span class="doctag">@see</span> #onProgressUpdate</div><div class="line">     * <span class="doctag">@see</span> #doInBackground</div><div class="line">     */</div><div class="line">    <span class="meta">@WorkerThread</span> <span class="comment">// 从工作线程发消息到主线程</span></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">publishProgress</span><span class="params">(Progress... values)</span> </span>&#123;</div><div class="line">        <span class="keyword">if</span> (!isCancelled()) &#123;</div><div class="line">            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,</div><div class="line">                    <span class="keyword">new</span> AsyncTaskResult&lt;Progress&gt;(<span class="keyword">this</span>, values)).sendToTarget();</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">finish</span><span class="params">(Result result)</span> </span>&#123;</div><div class="line">        <span class="keyword">if</span> (isCancelled()) &#123;</div><div class="line">            onCancelled(result);</div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">            onPostExecute(result);</div><div class="line">        &#125;</div><div class="line">        mStatus = Status.FINISHED;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">InternalHandler</span> <span class="keyword">extends</span> <span class="title">Handler</span> </span>&#123;</div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="title">InternalHandler</span><span class="params">()</span> </span>&#123;</div><div class="line">            <span class="keyword">super</span>(Looper.getMainLooper()); <span class="comment">// 创建一个Handler对象，使用的Looper是主线程的Looper，那么它处理的消息都将在主线程，这个很关键</span></div><div class="line">        &#125;</div><div class="line"></div><div class="line">        <span class="meta">@SuppressWarnings</span>(&#123;<span class="string">"unchecked"</span>, <span class="string">"RawUseOfParameterizedType"</span>&#125;)</div><div class="line">        <span class="meta">@Override</span></div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">handleMessage</span><span class="params">(Message msg)</span> </span>&#123;</div><div class="line">            AsyncTaskResult&lt;?&gt; result = (AsyncTaskResult&lt;?&gt;) msg.obj;</div><div class="line">            <span class="keyword">switch</span> (msg.what) &#123;</div><div class="line">                <span class="keyword">case</span> MESSAGE_POST_RESULT:</div><div class="line">                    <span class="comment">// There is only one result</span></div><div class="line">                    result.mTask.finish(result.mData[<span class="number">0</span>]);</div><div class="line">                    <span class="keyword">break</span>;</div><div class="line">                <span class="keyword">case</span> MESSAGE_POST_PROGRESS:</div><div class="line">                    result.mTask.onProgressUpdate(result.mData);</div><div class="line">                    <span class="keyword">break</span>;</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>看了上面的源码再回想下AsyncTask用法我们可以得到如下结论：</p>
<ol>
<li>主线程无需动态向工作线程发消息，只是初始化的时候传递一些参数</li>
<li>工作线程完成后，通过获取主线程的Looper，构建Handler将结果发送给主线程</li>
</ol>
<ul>
<li><p>UI Thread</p>
<p>  看了上面的两个案例，我们在来看看为什么我们使用的主线程可以直接使用消息系统而没有执行<code>Looper.prepare()</code>，<code>Looper.loop()</code> 之类的初始化工作呢。</p>
<p>  其实结论很简单，不可能不初始化，只是系统提前已经帮我们初始化好了，这部分的源码位于 <code>sdk/sources/android-xx/android/app/ActivityThread.java</code> 中：</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">ActivityThread</span> </span>&#123;</div><div class="line">...</div><div class="line">    <span class="keyword">final</span> H mH = <span class="keyword">new</span> H();</div><div class="line">...</div><div class="line"><span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">H</span> <span class="keyword">extends</span> <span class="title">Handler</span> </span>&#123;</div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> LAUNCH_ACTIVITY         = <span class="number">100</span>;</div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> PAUSE_ACTIVITY          = <span class="number">101</span>;</div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> PAUSE_ACTIVITY_FINISHING= <span class="number">102</span>;</div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> STOP_ACTIVITY_SHOW      = <span class="number">103</span>;</div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> STOP_ACTIVITY_HIDE      = <span class="number">104</span>;</div><div class="line">    ...</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">handleMessage</span><span class="params">(Message msg)</span> </span>&#123;</div><div class="line">      ...</div><div class="line">      <span class="keyword">switch</span> (msg.what) &#123;</div><div class="line">          <span class="keyword">case</span> LAUNCH_ACTIVITY: &#123;</div><div class="line">              Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, <span class="string">"activityStart"</span>);</div><div class="line">              <span class="keyword">final</span> ActivityClientRecord r = (ActivityClientRecord) msg.obj;</div><div class="line">              r.packageInfo = getPackageInfoNoCheck(</div><div class="line">                      r.activityInfo.applicationInfo, r.compatInfo);</div><div class="line">              handleLaunchActivity(r, <span class="keyword">null</span>, <span class="string">"LAUNCH_ACTIVITY"</span>);</div><div class="line">              Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);</div><div class="line">          &#125; <span class="keyword">break</span>;</div><div class="line">          <span class="keyword">case</span> RELAUNCH_ACTIVITY: &#123;</div><div class="line">              Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, <span class="string">"activityRestart"</span>);</div><div class="line">              ActivityClientRecord r = (ActivityClientRecord)msg.obj;</div><div class="line">              handleRelaunchActivity(r);</div><div class="line">              Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);</div><div class="line">          &#125; <span class="keyword">break</span>;</div><div class="line">          <span class="keyword">case</span> PAUSE_ACTIVITY: &#123;</div><div class="line">              Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, <span class="string">"activityPause"</span>);</div><div class="line">              SomeArgs args = (SomeArgs) msg.obj;</div><div class="line">              handlePauseActivity((IBinder) args.arg1, <span class="keyword">false</span>,</div><div class="line">                      (args.argi1 &amp; USER_LEAVING) != <span class="number">0</span>, args.argi2,</div><div class="line">                      (args.argi1 &amp; DONT_REPORT) != <span class="number">0</span>, args.argi3);</div><div class="line">              maybeSnapshot();</div><div class="line">              Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);</div><div class="line">          &#125; <span class="keyword">break</span>;</div><div class="line">          ...</div><div class="line">       &#125;</div><div class="line">       ...</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</div><div class="line">        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, <span class="string">"ActivityThreadMain"</span>);</div><div class="line">        SamplingProfilerIntegration.start();</div><div class="line"></div><div class="line">        <span class="comment">// CloseGuard defaults to true and can be quite spammy.  We</span></div><div class="line">        <span class="comment">// disable it here, but selectively enable it later (via</span></div><div class="line">        <span class="comment">// StrictMode) on debug builds, but using DropBox, not logs.</span></div><div class="line">        CloseGuard.setEnabled(<span class="keyword">false</span>);</div><div class="line"></div><div class="line">        Environment.initForCurrentUser();</div><div class="line"></div><div class="line">        <span class="comment">// Set the reporter for event logging in libcore</span></div><div class="line">        EventLogger.setReporter(<span class="keyword">new</span> EventLoggingReporter());</div><div class="line"></div><div class="line">        <span class="comment">// Make sure TrustedCertificateStore looks in the right place for CA certificates</span></div><div class="line">        <span class="keyword">final</span> File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());</div><div class="line">        TrustedCertificateStore.setDefaultUserDirectory(configDir);</div><div class="line"></div><div class="line">        Process.setArgV0(<span class="string">"&lt;pre-initialized&gt;"</span>);</div><div class="line"></div><div class="line">        Looper.prepareMainLooper(); <span class="comment">// 准备MainLooper</span></div><div class="line"></div><div class="line">        ActivityThread thread = <span class="keyword">new</span> ActivityThread();</div><div class="line">        thread.attach(<span class="keyword">false</span>);</div><div class="line"></div><div class="line">        <span class="keyword">if</span> (sMainThreadHandler == <span class="keyword">null</span>) &#123;</div><div class="line">            sMainThreadHandler = thread.getHandler();</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        <span class="keyword">if</span> (<span class="keyword">false</span>) &#123;</div><div class="line">            Looper.myLooper().setMessageLogging(<span class="keyword">new</span></div><div class="line">                    LogPrinter(Log.DEBUG, <span class="string">"ActivityThread"</span>));</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        <span class="comment">// End of event ActivityThreadMain.</span></div><div class="line">        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);</div><div class="line">        Looper.loop(); <span class="comment">// 启动这个消息循环</span></div><div class="line"></div><div class="line">        <span class="comment">// 当上面的Looper执行quit()的时候执行到这里，当然，这个时候app就要退出了</span></div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"Main thread loop unexpectedly exited"</span>);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>再回到我们文章开始的时候提到的问题：为什么通过 <code>view.post()</code> 可以获取到View的尺寸呢？</p>
<p>答：首先大家需要知道，我们Activity的启动，也是通过系统消息的方式触发的。从上面的代码中可以看到，当 <code>Looper.loop()</code> 执行之后，即可接收系统消息了，比如启动Activity之类的消息。当系统发出了一个启动Activity的消息，然后执行这个消息才会去启动Actvity，启动Activiy会调用它的生命周期方法，比如 <code>onCreate()</code> 等，在 <code>Activity.onCreate()</code> 中用view.post发一个任务到主线程的消息队列，那这个消息肯定要等之前的消息任务执行完，也就是当前创建Activity的消息执行完成之后才能执行。所以，我们就可以获取到View的尺寸了。</p>
<p>那么我们来验证一下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ViewPostActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> TextView tvInfo;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState);</div><div class="line">        setContentView(R.layout.activity_view_post);</div><div class="line"></div><div class="line">        printMsg(<span class="string">"onCreate"</span>);</div><div class="line"></div><div class="line">        tvInfo = (TextView) findViewById(R.id.tvInfo);</div><div class="line">        tvInfo.post(<span class="keyword">new</span> Runnable() &#123;</div><div class="line">            <span class="meta">@Override</span></div><div class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">                printMsg(<span class="string">"Width:"</span> + tvInfo.getWidth());</div><div class="line">                printMsg(<span class="string">"Height:"</span> + tvInfo.getHeight());</div><div class="line">            &#125;</div><div class="line">        &#125;);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onStart</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>.onStart();</div><div class="line"></div><div class="line">        printMsg(<span class="string">"onStart"</span>);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onResume</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>.onResume();</div><div class="line"></div><div class="line">        printMsg(<span class="string">"onResume"</span>);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">printMsg</span><span class="params">(String msg)</span> </span>&#123;</div><div class="line">        System.out.println(<span class="string">"&gt;&gt;&gt;&gt;&gt;"</span> + msg);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>输出的Log：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="number">07</span>-<span class="number">27</span> <span class="number">13</span>:<span class="number">06</span>:<span class="number">36.373</span> <span class="number">17506</span>-<span class="number">17506</span>/com.ttdevs.message I/System.out: &gt;&gt;&gt;&gt;&gt;onCreate</div><div class="line"><span class="number">07</span>-<span class="number">27</span> <span class="number">13</span>:<span class="number">06</span>:<span class="number">36.378</span> <span class="number">17506</span>-<span class="number">17506</span>/com.ttdevs.message I/System.out: &gt;&gt;&gt;&gt;&gt;onStart</div><div class="line"><span class="number">07</span>-<span class="number">27</span> <span class="number">13</span>:<span class="number">06</span>:<span class="number">36.378</span> <span class="number">17506</span>-<span class="number">17506</span>/com.ttdevs.message I/System.out: &gt;&gt;&gt;&gt;&gt;onResume</div><div class="line"><span class="number">07</span>-<span class="number">27</span> <span class="number">13</span>:<span class="number">06</span>:<span class="number">36.433</span> <span class="number">17506</span>-<span class="number">17506</span>/com.ttdevs.message I/System.out: &gt;&gt;&gt;&gt;&gt;Width:<span class="number">248</span></div><div class="line"><span class="number">07</span>-<span class="number">27</span> <span class="number">13</span>:<span class="number">06</span>:<span class="number">36.433</span> <span class="number">17506</span>-<span class="number">17506</span>/com.ttdevs.message I/System.out: &gt;&gt;&gt;&gt;&gt;Height:<span class="number">76</span></div></pre></td></tr></table></figure>
<p>和推测的一致，Coooool～～</p>
<p>最后，留个好玩的问题，执行 <code>getMainLooper().quit()</code> 会怎样呢？</p>
<p><a href="https://github.com/ttdevs/android/tree/master/apps/message" target="_blank" rel="external">源码参考这里</a></p>
<hr>
<p><img src="https://raw.githubusercontent.com/ttdevs/ttdevs.github.io/common/images/logo.png" alt="Create by ttdevs"></p>

          </section>
        </article>
        

       
        <div class="pager">
          
            <a class="post-prev pager-item" href="/2017/06/20/2017-06-20/" >
              <strong class="article-nav-caption">上一篇</strong>
              <p class="post-nav-title"></p>
            </a>
          
          
        </div>
        

         <!-- comments -->
        <div class="comment-section">
  
    


</div>

    </div>
    
    <aside>
        <div id="toc">
        </div>
    </aside>
    
</div>

                </div>
            </div>
        </div>
        <footer class="footer">
    <p>由<a href="http://hexo.io/" target="_blank">Hexo</a>强力驱动，搭载<a href="https://github.com/wayou/hexo-theme-gstyle">gstyle</a>主题</p>
    <p>
        &copy; 2017 ttdevs
    </p>
</footer>
<script src="/lib/jquery.js"></script>
<script src="/lib/waves.js"></script>
<script src="/lib/jquery-ui.js"></script>
<script src="/lib/jquery.tocify.js"></script>
<script src="/js/main.js"></script>

    </body>
</html>
